package myzd.utils;

import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

/**
 * @author zks
 * @since 2017/10/29 13:30
 */
public class IdCardUtils {

  private final static Map<Integer, String> zoneNum = new HashMap<>();

  static {
    zoneNum.put(11, "北京");
    zoneNum.put(12, "天津");
    zoneNum.put(13, "河北");
    zoneNum.put(14, "山西");
    zoneNum.put(15, "内蒙古");
    zoneNum.put(21, "辽宁");
    zoneNum.put(22, "吉林");
    zoneNum.put(23, "黑龙江");
    zoneNum.put(31, "上海");
    zoneNum.put(32, "江苏");
    zoneNum.put(33, "浙江");
    zoneNum.put(34, "安徽");
    zoneNum.put(35, "福建");
    zoneNum.put(36, "江西");
    zoneNum.put(37, "山东");
    zoneNum.put(41, "河南");
    zoneNum.put(42, "湖北");
    zoneNum.put(43, "湖南");
    zoneNum.put(44, "广东");
    zoneNum.put(45, "广西");
    zoneNum.put(46, "海南");
    zoneNum.put(50, "重庆");
    zoneNum.put(51, "四川");
    zoneNum.put(52, "贵州");
    zoneNum.put(53, "云南");
    zoneNum.put(54, "西藏");
    zoneNum.put(61, "陕西");
    zoneNum.put(62, "甘肃");
    zoneNum.put(63, "青海");
    zoneNum.put(64, "宁夏");
    zoneNum.put(65, "新疆");
    zoneNum.put(71, "台湾");
    zoneNum.put(81, "香港");
    zoneNum.put(82, "澳门");
    zoneNum.put(91, "国外");
  }

  private final static int[] PARITYBIT = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};
  private final static int[] POWER_LIST = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};

  public static boolean isIdcard(String number) {
    if (number == null || (number.length() != 15 && number.length() != 18)) {
      return false;
    }
    if (number.length() == 15) {
      number = number.substring(0, 6) + "19" + number.substring(6);
    }
    final char[] cs = number.toUpperCase().toCharArray();
    //校验各个位数是否为数字（最后一位除外）
    int power = 0;
    for (int i = 0; i < cs.length; i++) {
      if (i == cs.length - 1 && cs[i] == 'X') {
        break;
      }
      if (cs[i] < '0' || cs[i] > '9') {
        return false;
      }
      if (i < cs.length - 1) {
        power += (cs[i] - '0') * POWER_LIST[i];
      }
    }
    // （2）校验区位码
    if (!zoneNum.containsKey(Integer.valueOf(number.substring(0, 2)))) {
      return false;
    }
    final int year = Integer.valueOf(number.substring(6, 10));
    final int month = Integer.parseInt(number.substring(10, 12));
    final int day = Integer.parseInt(number.substring(12, 14));
    if (number.length() == 17) {
      return validate(year, month, day);
    }
    return validate(year, month, day) && cs[cs.length - 1] == PARITYBIT[power % 11];
  }


  private static boolean validate(int year, int month, int day) {
    return year <= Calendar.getInstance().get(Calendar.YEAR) && month >= 1 && month <= 12 && day >= 1 && day <= 31 && year >= 1900;
  }


}
